// import com.alibaba.druid.DbType_ptr;
// import com.alibaba.druid.FastsqlException;
// import com.alibaba.druid.sql.SQLUtils;
// import com.alibaba.druid.sql.ast.SQLDataType;
// import com.alibaba.druid.sql.ast.SQLExpr_ptr;
// import com.alibaba.druid.sql.ast.SQLName_ptr;
// import com.alibaba.druid.sql.ast.SQLStatement_ptr;
// import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr;
// import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
// import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
// import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
// import com.alibaba.druid.sql.ast.statement.*;
// import com.alibaba.druid.sql.dialect.hive.stmt.HiveCreateTableStatement;
// import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
// import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlRenameTableStatement;
// import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitorAdapter;
// import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateTableStatement;
// import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitorAdapter;
// import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerASTVisitorAdapter;
// import com.alibaba.druid.sql.parser.SQLParserFeature;
// import com.alibaba.druid.sql.repository.function.Function_ptr;
// import com.alibaba.druid.sql.visitor.SQLASTVisitor_ptr;
// import com.alibaba.druid.sql.visitor.SQLASTVisitorAdapter;
// import com.alibaba.druid.support.logging.Log;
// import com.alibaba.druid.support.logging.LogFactory;
// import com.alibaba.druid.util.FnvHash;

// import java.io.IOException;
// import java.util.Collection;
// import java.util.LinkedHashMap;
// import java.util.List;
// import java.util.std::map;
// import java.util.concurrent.ConcurrentHashMap;

#include "SchemaRepository.h"
#include "../dialect/hive/stmt/HiveCreateTableStatement.h"
#include "../dialect/mysql/ast/statement/MySqlCreateTableStatement.h"
#include "../dialect/mysql/ast/statement/MySqlRenameTableStatement.h"
#include "../ast/statement/SQLUseStatement.h"
#include "../ast/statement/SQLCreateSequenceStatement.h"
#include "../ast/statement/SQLShowColumnsStatement.h"
#include "../ast/statement/SQLShowCreateTableStatement.h"
#include "../ast/statement/SQLShowTablesStatement.h"
#include "../ast/statement/SQLDropIndexStatement.h"
#include "../ast/statement/SQLDropSequenceStatement.h"
#include "../ast/statement/SQLSelectStatement.h"
#include "../ast/statement/SQLSelectItem.h"
#include "../ast/statement/SQLDropTableStatement.h"
#include "../ast/statement/SQLColumnDefinition.h"
#include "../ast/expr/SQLAllColumnExpr.h"
#include "../../DbType.h"
#include "../SQLUtils.h"
#include "Schema.h"
#include "../../utils/StringUtils.h"
#include "../../utils/instanceof.h"
#include "../../utils/FnvHash.h"
#include "SchemaResolveVisitor.h"
#include "SchemaResolveVisitorFactory.h"
#include "SchemaObject.h"
#include "../../Exception/FastsqlException.h"
#include "SchemaObjectType.h"
#include "../visitor/SQLASTVisitor.h"

SchemaRepository_MySqlConsoleSchemaVisitor::SchemaRepository_MySqlConsoleSchemaVisitor(SchemaRepository *schemaRepository)
    : schemaRepository_(schemaRepository)
{
}

bool SchemaRepository_MySqlConsoleSchemaVisitor::visit(SQLDropSequenceStatement_ptr x)
{
  schemaRepository_->acceptDropSequence(x);
  return false;
}

BOOL_ptr SchemaRepository_MySqlConsoleSchemaVisitor::visit(SQLCreateSequenceStatement *x)
{
  schemaRepository_->acceptCreateSequence(x);
  return BOOL::FALSE;
}

BOOL_ptr SchemaRepository_MySqlConsoleSchemaVisitor::visit(HiveCreateTableStatement_ptr x)
{
  schemaRepository_->acceptCreateTable(x);
  return BOOL::FALSE;
}

BOOL_ptr SchemaRepository_MySqlConsoleSchemaVisitor::visit(MySqlCreateTableStatement_ptr x)
{
  schemaRepository_->acceptCreateTable(x);
  return BOOL::FALSE;
}

bool SchemaRepository_MySqlConsoleSchemaVisitor::visit(SQLCreateTableStatement_ptr x)
{
  schemaRepository_->acceptCreateTable(x);
  return false;
}

bool SchemaRepository_MySqlConsoleSchemaVisitor::visit(SQLDropTableStatement_ptr x)
{
  schemaRepository_->acceptDropTable(x);
  return false;
}

// BOOL_ptr SchemaRepository_MySqlConsoleSchemaVisitor::visit(SQLCreateViewStatement *x)
// {
//   acceptView(x);
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaRepository_MySqlConsoleSchemaVisitor::visit(SQLAlterViewStatement *x)
// {
//   acceptView(x);
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaRepository_MySqlConsoleSchemaVisitor::visit(SQLCreateIndexStatement *x)
// {
//   acceptCreateIndex(x);
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaRepository_MySqlConsoleSchemaVisitor::visit(SQLCreateFunctionStatement *x)
// {
//   acceptCreateFunction(x);
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaRepository_MySqlConsoleSchemaVisitor::visit(SQLAlterTableStatement *x)
// {
//   acceptAlterTable(x);
//   return BOOL::FALSE;
// }

BOOL_ptr SchemaRepository_MySqlConsoleSchemaVisitor::visit(SQLUseStatement *x)
{
  string_ptr schema = x->getDatabase()->getSimpleName();
  schemaRepository_->setDefaultSchema(schema);
  return BOOL::FALSE;
}

bool SchemaRepository_MySqlConsoleSchemaVisitor::visit(SQLDropIndexStatement_ptr x)
{
  schemaRepository_->acceptDropIndex(x);
  return false;
}

SchemaRepository_OracleConsoleSchemaVisitor::SchemaRepository_OracleConsoleSchemaVisitor(SchemaRepository *schemaRepository)
    : schemaRepository_(schemaRepository)
{
}

bool SchemaRepository_OracleConsoleSchemaVisitor::visit(SQLDropSequenceStatement_ptr x)
{
  schemaRepository_->acceptDropSequence(x);
  return false;
}

BOOL_ptr SchemaRepository_OracleConsoleSchemaVisitor::visit(SQLCreateSequenceStatement *x)
{
  schemaRepository_->acceptCreateSequence(x);
  return BOOL::FALSE;
}

// BOOL_ptr SchemaRepository_OracleConsoleSchemaVisitor::visit(OracleCreateTableStatement *x)
// {
//   schemaRepository_->visit((SQLCreateTableStatement)x);
//   return BOOL::FALSE;
// }

bool SchemaRepository_OracleConsoleSchemaVisitor::visit(SQLCreateTableStatement_ptr x)
{
  schemaRepository_->acceptCreateTable(x);
  return false;
}

bool SchemaRepository_OracleConsoleSchemaVisitor::visit(SQLDropTableStatement_ptr x)
{
  schemaRepository_->acceptDropTable(x);
  return false;
}

// BOOL_ptr SchemaRepository_OracleConsoleSchemaVisitor::visit(SQLCreateViewStatement *x)
// {
//   schemaRepository_->acceptView(x);
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaRepository_OracleConsoleSchemaVisitor::visit(SQLAlterViewStatement *x)
// {
//   schemaRepository_->acceptView(x);
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaRepository_OracleConsoleSchemaVisitor::visit(SQLCreateIndexStatement *x)
// {
//   schemaRepository_->acceptCreateIndex(x);
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaRepository_OracleConsoleSchemaVisitor::visit(SQLCreateFunctionStatement *x)
// {
//   schemaRepository_->acceptCreateFunction(x);
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaRepository_OracleConsoleSchemaVisitor::visit(SQLAlterTableStatement *x)
// {
//   schemaRepository_->acceptAlterTable(x);
//   return BOOL::FALSE;
// }

BOOL_ptr SchemaRepository_OracleConsoleSchemaVisitor::visit(SQLUseStatement *x)
{
  string_ptr schema = x->getDatabase()->getSimpleName();
  schemaRepository_->setDefaultSchema(schema);
  return BOOL::FALSE;
}

bool SchemaRepository_OracleConsoleSchemaVisitor::visit(SQLDropIndexStatement_ptr x)
{
  schemaRepository_->acceptDropIndex(x);
  return false;
}

SchemaRepository_SqlServerConsoleSchemaVisitor::SchemaRepository_SqlServerConsoleSchemaVisitor(SchemaRepository *schemaRepository)
    : schemaRepository_(schemaRepository)
{
}

SchemaRepository_SqlServerConsoleSchemaVisitor::SchemaRepository_SqlServerConsoleSchemaVisitor()
{
  schemaRepository_->dbType = DbType_ptr(new DbType(&DbType::sqlserver));
}

bool SchemaRepository_SqlServerConsoleSchemaVisitor::visit(SQLDropSequenceStatement_ptr x)
{
  schemaRepository_->acceptDropSequence(x);
  return false;
}

BOOL_ptr SchemaRepository_SqlServerConsoleSchemaVisitor::visit(SQLCreateSequenceStatement *x)
{
  schemaRepository_->acceptCreateSequence(x);
  return BOOL::FALSE;
}

// BOOL_ptr SchemaRepository_SqlServerConsoleSchemaVisitor::visit(OracleCreateTableStatement *x)
// {
//   visit((SQLCreateTableStatement)x);
//   return BOOL::FALSE;
// }

bool SchemaRepository_SqlServerConsoleSchemaVisitor::visit(SQLCreateTableStatement_ptr x)
{
  schemaRepository_->acceptCreateTable(x);
  return false;
}

bool SchemaRepository_SqlServerConsoleSchemaVisitor::visit(SQLDropTableStatement_ptr x)
{
  schemaRepository_->acceptDropTable(x);
  return false;
}

// BOOL_ptr SchemaRepository_SqlServerConsoleSchemaVisitor::visit(SQLCreateViewStatement *x)
// {
//   schemaRepository_->acceptView(x);
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaRepository_SqlServerConsoleSchemaVisitor::visit(SQLAlterViewStatement *x)
// {
//   schemaRepository_->acceptView(x);
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaRepository_SqlServerConsoleSchemaVisitor::visit(SQLCreateIndexStatement *x)
// {
//   schemaRepository_->acceptCreateIndex(x);
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaRepository_SqlServerConsoleSchemaVisitor::visit(SQLCreateFunctionStatement *x)
// {
//   schemaRepository_->acceptCreateFunction(x);
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaRepository_SqlServerConsoleSchemaVisitor::visit(SQLAlterTableStatement *x)
// {
//   schemaRepository_->acceptAlterTable(x);
//   return BOOL::FALSE;
// }

BOOL_ptr SchemaRepository_SqlServerConsoleSchemaVisitor::visit(SQLUseStatement *x)
{
  string_ptr schema = x->getDatabase()->getSimpleName();
  schemaRepository_->setDefaultSchema(schema);
  return BOOL::FALSE;
}

bool SchemaRepository_SqlServerConsoleSchemaVisitor::visit(SQLDropIndexStatement_ptr x)
{
  schemaRepository_->acceptDropIndex(x);
  return false;
}

SchemaRepository_DefaultConsoleSchemaVisitor::SchemaRepository_DefaultConsoleSchemaVisitor(SchemaRepository *schemaRepository)
    : schemaRepository_(schemaRepository)
{
}

bool SchemaRepository_DefaultConsoleSchemaVisitor::visit(SQLDropSequenceStatement_ptr x)
{
  schemaRepository_->acceptDropSequence(x);
  return false;
}

BOOL_ptr SchemaRepository_DefaultConsoleSchemaVisitor::visit(SQLCreateSequenceStatement *x)
{
  schemaRepository_->acceptCreateSequence(x);
  return BOOL::FALSE;
}

bool SchemaRepository_DefaultConsoleSchemaVisitor::visit(SQLCreateTableStatement_ptr x)
{
  schemaRepository_->acceptCreateTable(x);
  return false;
}

BOOL_ptr SchemaRepository_DefaultConsoleSchemaVisitor::visit(HiveCreateTableStatement_ptr x)
{
  schemaRepository_->acceptCreateTable(x);
  return BOOL::FALSE;
}

bool SchemaRepository_DefaultConsoleSchemaVisitor::visit(SQLDropTableStatement_ptr x)
{
  schemaRepository_->acceptDropTable(x);
  return false;
}

// BOOL_ptr SchemaRepository_DefaultConsoleSchemaVisitor::visit(SQLCreateViewStatement *x)
// {
//   schemaRepository_->acceptView(x);
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaRepository_DefaultConsoleSchemaVisitor::visit(SQLAlterViewStatement *x)
// {
//   schemaRepository_->acceptView(x);
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaRepository_DefaultConsoleSchemaVisitor::visit(SQLCreateIndexStatement *x)
// {
//   schemaRepository_->acceptCreateIndex(x);
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaRepository_DefaultConsoleSchemaVisitor::visit(SQLCreateFunctionStatement *x)
// {
//   schemaRepository_->acceptCreateFunction(x);
//   return BOOL::FALSE;
// }

// BOOL_ptr SchemaRepository_DefaultConsoleSchemaVisitor::visit(SQLAlterTableStatement *x)
// {
//   schemaRepository_->acceptAlterTable(x);
//   return BOOL::FALSE;
// }

bool SchemaRepository_DefaultConsoleSchemaVisitor::visit(SQLDropIndexStatement_ptr x)
{
  schemaRepository_->acceptDropIndex(x);
  return false;
}

SchemaRepository::SchemaRepository()
{
}

SchemaRepository::SchemaRepository(DbType_ptr dbType)
    : SchemaRepository(dbType, dbType)
{
}

SchemaRepository::SchemaRepository(DbType_ptr dbType, DbType_ptr schemaDbType)
{
  if (dbType == nullptr)
  {
    dbType = DbType_ptr(new DbType(&DbType::other));
  }
  if (schemaDbType == nullptr)
  {
    schemaDbType = dbType;
  }

  this->dbType = dbType;
  this->schemaDbType = schemaDbType;

  if (*dbType == DbType::mysql)
  {
    consoleVisitor = std::dynamic_pointer_cast<SQLASTVisitor>(SchemaRepository_MySqlConsoleSchemaVisitor_ptr(new SchemaRepository_MySqlConsoleSchemaVisitor(this)));
  }
  else if (*dbType == DbType::oracle)
  {
    consoleVisitor = std::dynamic_pointer_cast<SQLASTVisitor>(SchemaRepository_OracleConsoleSchemaVisitor_ptr(new SchemaRepository_OracleConsoleSchemaVisitor(this)));
  }
  else if (*dbType == DbType::sqlserver)
  {
    consoleVisitor = std::dynamic_pointer_cast<SQLASTVisitor>(SchemaRepository_SqlServerConsoleSchemaVisitor_ptr(new SchemaRepository_SqlServerConsoleSchemaVisitor(this)));
  }
  else
  {
    consoleVisitor = std::dynamic_pointer_cast<SQLASTVisitor>(SchemaRepository_DefaultConsoleSchemaVisitor_ptr(new SchemaRepository_DefaultConsoleSchemaVisitor(this)));
  }
}

DbType_ptr SchemaRepository::getDbType()
{
  return dbType;
}

string_ptr SchemaRepository::getDefaultSchemaName()
{
  return getDefaultSchema()->getName();
}

void SchemaRepository::setDefaultSchema(string_ptr name)
{
  if (name == nullptr)
  {
    defaultSchema = nullptr;
    return;
  }

  string_ptr normalizedName = StringUtils::toLower(SQLUtils::normalize(name));

  auto tmp = schemas.find(normalizedName->c_str());
  Schema_ptr defaultSchema = nullptr;
  if (tmp != schemas.end())
  {
    defaultSchema = tmp->second;
  }
  if (defaultSchema != nullptr)
  {
    this->defaultSchema = defaultSchema;
    return;
  }

  if (this->defaultSchema != nullptr && this->defaultSchema->getName() == nullptr)
  {
    this->defaultSchema->setName(name);

    schemas.insert(std::make_pair(normalizedName->c_str(), this->defaultSchema));
    return;
  }

  defaultSchema = Schema_ptr(new Schema(SharedObject(SchemaRepository)   ));
  defaultSchema->setName(name);
  schemas.insert(std::make_pair(normalizedName->c_str(), defaultSchema));
  this->defaultSchema = defaultSchema;
}

Schema_ptr SchemaRepository::findSchema(string_ptr schema)
{
  return findSchema(schema, BOOL::FALSE);
}

Schema_ptr SchemaRepository::findSchema(string_ptr name, BOOL_ptr create)
{
  if (name == nullptr || name->length() == 0)
  {
    return getDefaultSchema();
  }

  name = SQLUtils::normalize(name);
  string_ptr normalizedName = StringUtils::toLower(name);

  if (getDefaultSchema() != nullptr && defaultSchema->getName() == nullptr && create)
  {
    defaultSchema->setName(name);
    schemas.insert(std::make_pair(normalizedName->c_str(), defaultSchema));
    return defaultSchema;
  }

  auto tmp = schemas.find(normalizedName->c_str());
  Schema_ptr schema = nullptr;
  if (tmp != schemas.end())
  {
    schema = tmp->second;
  }

  if (schema == nullptr && create)
  {
    int p = name->find('.');

    string_ptr catalog = nullptr;
    if (p != -1)
    {
      catalog = make_string_ptr(name->substr(0, p));
    }
    schema = Schema_ptr(new Schema(SharedObject(SchemaRepository)   , catalog, name));
    schemas.insert(std::make_pair(normalizedName->c_str(), schema));
  }
  return schema;
}

Schema_ptr SchemaRepository::getDefaultSchema()
{
  if (defaultSchema == nullptr)
  {
    defaultSchema = Schema_ptr(new Schema(SharedObject(SchemaRepository)   ));
  }

  return defaultSchema;
}

void SchemaRepository::setDefaultSchema(Schema_ptr schema)
{
  this->defaultSchema = schema;
}

SchemaObject_ptr SchemaRepository::findTable(string_ptr tableName)
{
  if (tableName->find('.') != -1)
  {
    SQLExpr_ptr expr = SQLUtils::toSQLExpr(tableName, dbType);
    if (!(instanceof <SQLExpr, SQLIdentifierExpr>(expr)))
    {
      return findTable(std::dynamic_pointer_cast<SQLName>(expr));
    }
  }
  SchemaObject_ptr object = getDefaultSchema()->findTable(tableName);

  if (object != nullptr)
  {
    return object;
  }

  string_ptr ddl = loadDDL(tableName);
  if (ddl == nullptr)
  {
    return nullptr;
  }

  DbType_ptr schemaDbType = this->schemaDbType;
  if (schemaDbType == nullptr)
  {
    schemaDbType = dbType;
  }

  SchemaObject_ptr schemaObject = acceptDDL(ddl, schemaDbType);
  if (schemaObject != nullptr)
  {
    return schemaObject;
  }

  return getDefaultSchema()->findTable(tableName);
}

SchemaObject_ptr SchemaRepository::findView(string_ptr viewName)
{
  SchemaObject_ptr object = getDefaultSchema()->findView(viewName);

  if (object != nullptr)
  {
    return object;
  }

  string_ptr ddl = loadDDL(viewName);
  if (ddl == nullptr)
  {
    return nullptr;
  }

  acceptDDL(ddl);

  return getDefaultSchema()->findView(viewName);
}

SchemaObject_ptr SchemaRepository::findTable(long tableNameHash)
{
  return getDefaultSchema()->findTable(tableNameHash);
}

SchemaObject_ptr SchemaRepository::findTableOrView(string_ptr tableName)
{
  return findTableOrView(tableName, BOOL::TRUE);
}

SchemaObject_ptr SchemaRepository::findTableOrView(string_ptr tableName, BOOL_ptr onlyCurrent)
{
  Schema_ptr schema = getDefaultSchema();

  SchemaObject_ptr object = schema->findTableOrView(tableName);
  if (object != nullptr)
  {
    return object;
  }

  // for (Schema_ptr s : this->schemas.values())
  for (auto tmp : this->schemas)
  {
    Schema_ptr s = tmp.second;

    if (s == schema)
    {
      continue;
    }

    object = schema->findTableOrView(tableName);
    if (object != nullptr)
    {
      return object;
    }
  }

  string_ptr ddl = loadDDL(tableName);
  if (ddl == nullptr)
  {
    return nullptr;
  }

  acceptDDL(ddl);

  // double check
  object = schema->findTableOrView(tableName);
  if (object != nullptr)
  {
    return object;
  }

  // for (Schema_ptr s : this->schemas.values())
  for (auto tmp : this->schemas)
  {
    Schema_ptr s = tmp.second;

    if (s == schema)
    {
      continue;
    }

    object = schema->findTableOrView(tableName);
    if (object != nullptr)
    {
      return object;
    }
  }

  return nullptr;
}

Schema_list_ptr SchemaRepository::getSchemas()
{
  // return schemas.values();
  Schema_list_ptr out = std::make_shared<std::list<Schema_ptr>>();
  for (auto tmp : this->schemas)
  {
    out->push_back(tmp.second);
  }
  return out;
}

SchemaObject_ptr SchemaRepository::findFunction(string_ptr functionName)
{
  return getDefaultSchema()->findFunction(functionName);
}

void SchemaRepository::acceptDDL(string_ptr ddl)
{
  acceptDDL(ddl, schemaDbType);
}

SchemaObject_ptr SchemaRepository::acceptDDL(string_ptr ddl, DbType_ptr dbType)
{
  SQLStatement_list_ptr stmtList = SQLUtils::parseStatements(ddl, dbType);
  for (SQLStatement_ptr stmt : *stmtList)
  {
    if (instanceof <SQLStatement, SQLCreateTableStatement>(stmt))
    {
      SchemaObject_ptr schemaObject = acceptCreateTable(std::dynamic_pointer_cast<SQLCreateTableStatement>(stmt));
      if (stmtList->size() == 1)
      {
        return schemaObject;
      }
    }
    // else if (stmt instanceof SQLCreateViewStatement)
    // {
    //   SchemaObject_ptr schemaObject = acceptView((SQLCreateViewStatement)stmt);
    //   if (stmtList.size() == 1)
    //   {
    //     return schemaObject;
    //   }
    // }
    else
    {
      accept(stmt);
    }
  }

  return nullptr;
}

void SchemaRepository::accept(SQLStatement_ptr stmt)
{
  stmt->accept(consoleVisitor);
}

BOOL_ptr SchemaRepository::isSequence(string_ptr name)
{
  return getDefaultSchema()->isSequence(name);
}

SchemaObject_ptr SchemaRepository::findTable(SQLTableSource_ptr tableSource, string_ptr alias)
{
  return getDefaultSchema()->findTable(tableSource, alias);
}

SQLColumnDefinition_ptr SchemaRepository::findColumn(SQLTableSource_ptr tableSource, SQLSelectItem_ptr selectItem)
{
  return getDefaultSchema()->findColumn(tableSource, selectItem);
}

SQLColumnDefinition_ptr SchemaRepository::findColumn(SQLTableSource_ptr tableSource, SQLExpr_ptr expr)
{
  return getDefaultSchema()->findColumn(tableSource, expr);
}

SchemaObject_ptr SchemaRepository::findTable(SQLTableSource_ptr tableSource, SQLSelectItem_ptr selectItem)
{
  return getDefaultSchema()->findTable(tableSource, selectItem);
}

SchemaObject_ptr SchemaRepository::findTable(SQLTableSource_ptr tableSource, SQLExpr_ptr expr)
{
  return getDefaultSchema()->findTable(tableSource, expr);
}

std::unordered_map<std::string, SchemaObject_ptr> SchemaRepository::getTables(SQLTableSource_ptr x)
{
  return getDefaultSchema()->getTables(x);
}

BOOL_ptr SchemaRepository::removeTable(SQLName_ptr name)
{
  return getDefaultSchema()->removeObject(name->nameHashCode64());
}

int SchemaRepository::getTableCount()
{
  return getDefaultSchema()->getTableCount();
}

SchemaObject_list_ptr SchemaRepository::getObjects()
{
  return getDefaultSchema()->getObjects();
}

int SchemaRepository::getViewCount()
{
  return getDefaultSchema()->getViewCount();
}

void SchemaRepository::resolve(SQLSelectStatement_ptr stmt, SchemaResolveVisitor_Option_list_ptr options)
{
  if (stmt == nullptr)
  {
    return;
  }

  SchemaResolveVisitor_ptr resolveVisitor = createResolveVisitor(options);
  resolveVisitor->visit(stmt);
}

void SchemaRepository::resolve(SQLSelect_ptr select, SchemaResolveVisitor_Option_list_ptr options)
{
  if (select == nullptr)
  {
    return;
  }

  SchemaResolveVisitor_ptr resolveVisitor = createResolveVisitor(options);
  resolveVisitor->visit(select);
}

void SchemaRepository::resolve(SQLSelectQueryBlock_ptr queryBlock, SchemaResolveVisitor_Option_list_ptr options)
{
  if (queryBlock == nullptr)
  {
    return;
  }

  SchemaResolveVisitor_ptr resolveVisitor = createResolveVisitor(options);
  resolveVisitor->visit(queryBlock);
}

void SchemaRepository::resolve(SQLStatement_ptr stmt, SchemaResolveVisitor_Option_list_ptr options)
{
  if (stmt == nullptr)
  {
    return;
  }

  SchemaResolveVisitor_ptr resolveVisitor = createResolveVisitor(options);
  if (instanceof <SQLStatement, SQLSelectStatement>(stmt))
  {
    resolveVisitor->visit(std::dynamic_pointer_cast<SQLSelectStatement>(stmt));
  }
  else
  {
    stmt->accept(resolveVisitor);
  }
}

SchemaResolveVisitor_ptr SchemaRepository::createResolveVisitor(SchemaResolveVisitor_Option_list_ptr options)
{
  int optionsValue = SchemaResolveVisitor_Option::of(options);

  SchemaResolveVisitor_ptr resolveVisitor;
  if (dbType->mask == DbType::mysql.mask ||
      dbType->mask == DbType::mariadb.mask ||
      dbType->mask == DbType::tidb.mask ||
      dbType->mask == DbType::sqlite.mask)
  {
    resolveVisitor = SchemaResolveVisitorFactory_MySqlResolveVisitor_ptr(new SchemaResolveVisitorFactory_MySqlResolveVisitor(SharedObject(SchemaRepository)   , optionsValue));
  }
  else if (dbType->mask == DbType::oracle.mask)
  {
    resolveVisitor = SchemaResolveVisitorFactory_OracleResolveVisitor_ptr(new SchemaResolveVisitorFactory_OracleResolveVisitor(SharedObject(SchemaRepository)   , optionsValue));
    // } else if (dbType->mask == DbType::db2.mask) {
    //   resolveVisitor = new SchemaResolveVisitorFactory_DB2ResolveVisitor(this, optionsValue);
    // } else if (dbType->mask == DbType::odps.mask) {
    //   resolveVisitor = new SchemaResolveVisitorFactory_OdpsResolveVisitor(this, optionsValue);
    // } else if (dbType->mask == DbType::hive.mask) {
    //   resolveVisitor = new SchemaResolveVisitorFactory_HiveResolveVisitor(this, optionsValue);
    // } else if (dbType->mask == DbType::postgresql.mask ||
    //            dbType->mask == DbType::edb.mask) {
    //   resolveVisitor = new SchemaResolveVisitorFactory_PGResolveVisitor(this, optionsValue);
  }
  else if (dbType->mask == DbType::sqlserver.mask)
  {
    resolveVisitor = SchemaResolveVisitorFactory_SQLServerResolveVisitor_ptr(new SchemaResolveVisitorFactory_SQLServerResolveVisitor(SharedObject(SchemaRepository)   , optionsValue));
  }
  else
  {
    resolveVisitor = SchemaResolveVisitorFactory_SQLResolveVisitor_ptr(new SchemaResolveVisitorFactory_SQLResolveVisitor(SharedObject(SchemaRepository)   , optionsValue));
  }

  return resolveVisitor;
}

string_ptr SchemaRepository::resolve(string_ptr input)
{
  SchemaResolveVisitor_Option_list_ptr options = std::make_shared<std::list<SchemaResolveVisitor_Option_ptr>>();
  options->push_back(SchemaResolveVisitor_Option::ResolveAllColumn);
  options->push_back(SchemaResolveVisitor_Option::ResolveIdentifierAlias);
  SchemaResolveVisitor_ptr visitor = createResolveVisitor(options);

  SQLStatement_list_ptr stmtList = SQLUtils::parseStatements(input, dbType);

  for (SQLStatement_ptr stmt : *stmtList)
  {
    stmt->accept(visitor);
  }

  return SQLUtils::toSQLString(stmtList, dbType);
}

string_ptr SchemaRepository::console(string_ptr input)
{
  try
  {
    std::stringstream buf;

    SQLParserFeature_list_ptr features = std::make_shared<std::list<SQLParserFeature_ptr>>();
    features->push_back(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::IgnoreNameQuotes)));
    SQLStatement_list_ptr stmtList = SQLUtils::parseStatements(input, dbType, features);

    for (SQLStatement_ptr stmt : *stmtList)
    {
      if (instanceof <SQLStatement, SQLShowColumnsStatement>(stmt))
      {
        SQLShowColumnsStatement_ptr showColumns = (std::dynamic_pointer_cast<SQLShowColumnsStatement>(stmt));
        SQLName_ptr db = showColumns->getDatabase();
        Schema_ptr schema;
        if (db == nullptr)
        {
          schema = getDefaultSchema();
        }
        else
        {
          schema = findSchema(db->getSimpleName());
        }

        SQLName_ptr table = nullptr;
        SchemaObject_ptr schemaObject = nullptr;
        if (schema != nullptr)
        {
          table = showColumns->getTable();
          schemaObject = schema->findTable(table->nameHashCode64());
        }

        if (schemaObject == nullptr)
        {
          buf << "ERROR 1146 (42S02): Table '";
          buf << table->getSimpleName()->c_str();
          buf << "' doesn't exist\n";
        }
        else
        {
          MySqlCreateTableStatement_ptr createTableStmt = std::dynamic_pointer_cast<MySqlCreateTableStatement>(schemaObject->getStatement());
          createTableStmt->showCoumns(&buf);
        }
      }
      else if (instanceof <SQLStatement, SQLShowCreateTableStatement>(stmt))
      {
        SQLShowCreateTableStatement_ptr showCreateTableStmt = std::dynamic_pointer_cast<SQLShowCreateTableStatement>(stmt);
        SQLName_ptr table = showCreateTableStmt->getName();
        SchemaObject_ptr schemaObject = findTable(table);
        if (schemaObject == nullptr)
        {
          buf << "ERROR 1146 (42S02): Table '";
          buf << table->getSimpleName()->c_str();
          buf << "' doesn't exist\n";
        }
        else
        {
          MySqlCreateTableStatement_ptr createTableStmt = std::dynamic_pointer_cast<MySqlCreateTableStatement>(schemaObject->getStatement());
          createTableStmt->output(&buf);
        }
      }
      else if (instanceof <SQLStatement, MySqlRenameTableStatement>(stmt))
      {
        MySqlRenameTableStatement_ptr renameStmt = std::dynamic_pointer_cast<MySqlRenameTableStatement>(stmt);
        for (MySqlRenameTableStatement_Item_ptr item : *renameStmt->getItems())
        {
          renameTable(item->getName(), item->getTo());
        }
      }
      else if (instanceof <SQLStatement, SQLShowTablesStatement>(stmt))
      {
        SQLShowTablesStatement_ptr showTables = std::dynamic_pointer_cast<SQLShowTablesStatement>(stmt);
        SQLName_ptr database = showTables->getDatabase();

        Schema_ptr schema;
        if (database == nullptr)
        {
          schema = getDefaultSchema();
        }
        else
        {
          schema = findSchema(database->getSimpleName());
        }
        if (schema != nullptr)
        {
          for (string_ptr table : *schema->showTables())
          {
            buf << table->c_str();
            buf << "\n";
          }
        }
      }
      else
      {
        stmt->accept(consoleVisitor);
      }
    }

    if (buf.str().length() == 0)
    {
      return make_string_ptr("\n");
    }

    return make_string_ptr(buf.str());
  }
  catch (const std::exception &e)
  {
    std::string tmp = "exeucte command error.";
    tmp += e.what();
    throw new FastsqlException(make_string_ptr(tmp));
  }
}

SchemaObject_ptr SchemaRepository::findTable(SQLName_ptr name)
{
  if (instanceof <SQLName, SQLIdentifierExpr>(name))
  {
    return findTable((std::dynamic_pointer_cast<SQLIdentifierExpr>(name))->getName());
  }

  if (instanceof <SQLName, SQLPropertyExpr>(name))
  {
    SQLPropertyExpr_ptr propertyExpr = std::dynamic_pointer_cast<SQLPropertyExpr>(name);
    SQLExpr_ptr owner = propertyExpr->getOwner();
    string_ptr schema;
    string_ptr catalog = nullptr;
    if (instanceof <SQLExpr, SQLIdentifierExpr>(owner))
    {
      schema = (std::dynamic_pointer_cast<SQLIdentifierExpr>(owner))->getName();
    }
    else if (instanceof <SQLExpr, SQLPropertyExpr>(owner))
    {
      schema = (std::dynamic_pointer_cast<SQLPropertyExpr>(owner))->getName();
      catalog = (std::dynamic_pointer_cast<SQLPropertyExpr>(owner))->getOwnernName();
    }
    else
    {
      return nullptr;
    }

    long tableHashCode64 = propertyExpr->nameHashCode64();

    Schema_ptr schemaObj = findSchema(schema, BOOL::FALSE);
    if (schemaObj != nullptr)
    {
      SchemaObject_ptr table = schemaObj->findTable(tableHashCode64);
      if (table != nullptr)
      {
        return table;
      }
    }

    string_ptr ddl = loadDDL(catalog, schema, propertyExpr->getName());

    if (ddl == nullptr)
    {
      schemaObj = findSchema(schema, BOOL::TRUE);
    }
    else
    {
      SQLStatement_list_ptr stmtList = SQLUtils::parseStatements(ddl, schemaDbType);
      for (SQLStatement_ptr stmt : *stmtList)
      {
        accept(stmt);
      }

      if (stmtList->size() == 1)
      {
        SQLStatement_ptr stmt = *stmtList->begin();
        if (instanceof <SQLStatement, SQLCreateTableStatement>(stmt))
        {
          SQLCreateTableStatement_ptr createStmt = std::dynamic_pointer_cast<SQLCreateTableStatement>(stmt);
          string_ptr schemaName = createStmt->getSchema();
          schemaObj = findSchema(schemaName, BOOL::TRUE);
        }
      }
    }

    if (schemaObj == nullptr)
    {
      return nullptr;
    }

    return schemaObj->findTable(tableHashCode64);
  }

  return nullptr;
}

SchemaObject_ptr SchemaRepository::findView(SQLName_ptr name)
{
  if (instanceof <SQLName, SQLIdentifierExpr>(name))
  {
    return findView((std::dynamic_pointer_cast<SQLIdentifierExpr>(name))->getName());
  }

  if (instanceof <SQLName, SQLPropertyExpr>(name))
  {
    SQLPropertyExpr_ptr propertyExpr = std::dynamic_pointer_cast<SQLPropertyExpr>(name);
    SQLExpr_ptr owner = propertyExpr->getOwner();
    string_ptr schema;
    string_ptr catalog = nullptr;
    if (instanceof <SQLExpr, SQLIdentifierExpr>(owner))
    {
      schema = (std::dynamic_pointer_cast<SQLIdentifierExpr>(owner))->getName();
    }
    else if (instanceof <SQLExpr, SQLPropertyExpr>(owner))
    {
      schema = (std::dynamic_pointer_cast<SQLPropertyExpr>(owner))->getName();
      catalog = (std::dynamic_pointer_cast<SQLPropertyExpr>(owner))->getOwnernName();
    }
    else
    {
      return nullptr;
    }

    long tableHashCode64 = propertyExpr->nameHashCode64();

    Schema_ptr schemaObj = findSchema(schema, BOOL::FALSE);
    if (schemaObj != nullptr)
    {
      SchemaObject_ptr table = schemaObj->findView(tableHashCode64);
      if (table != nullptr)
      {
        return table;
      }
    }

    string_ptr ddl = loadDDL(catalog, schema, propertyExpr->getName());

    if (ddl == nullptr)
    {
      schemaObj = findSchema(schema, BOOL::TRUE);
    }
    else
    {
      SQLStatement_list_ptr stmtList = SQLUtils::parseStatements(ddl, schemaDbType);
      for (SQLStatement_ptr stmt : *stmtList)
      {
        accept(stmt);
      }

      if (stmtList->size() == 1)
      {
        SQLStatement_ptr stmt = *stmtList->begin();
        if (instanceof <SQLStatement, SQLCreateTableStatement>(stmt))
        {
          SQLCreateTableStatement_ptr createStmt = std::dynamic_pointer_cast<SQLCreateTableStatement>(stmt);
          string_ptr schemaName = createStmt->getSchema();
          schemaObj = findSchema(schemaName, BOOL::TRUE);
        }
      }
    }

    if (schemaObj == nullptr)
    {
      return nullptr;
    }

    return schemaObj->findView(tableHashCode64);
  }

  return nullptr;
}

BOOL_ptr SchemaRepository::renameTable(SQLName_ptr name, SQLName_ptr to)
{
  Schema_ptr schema;
  if (instanceof <SQLName, SQLPropertyExpr>(name))
  {
    string_ptr schemaName = (std::dynamic_pointer_cast<SQLPropertyExpr>(name))->getOwnernName();
    schema = findSchema(schemaName);
  }
  else
  {
    schema = getDefaultSchema();
  }

  if (schema == nullptr)
  {
    return BOOL::FALSE;
  }

  long nameHashCode64 = name->nameHashCode64();
  SchemaObject_ptr schemaObject = schema->findTable(nameHashCode64);
  if (schemaObject != nullptr)
  {
    MySqlCreateTableStatement_ptr createTableStmt = std::dynamic_pointer_cast<MySqlCreateTableStatement>(schemaObject->getStatement());
    if (createTableStmt != nullptr)
    {
      createTableStmt->setName(std::dynamic_pointer_cast<SQLName>(to->clone()));
      acceptCreateTable(createTableStmt);
    }

    schema->objects.erase(nameHashCode64);
  }
  return BOOL::TRUE;
}

SchemaObject_ptr SchemaRepository::findTable(SQLExprTableSource_ptr x)
{
  if (x == nullptr)
  {
    return nullptr;
  }

  SQLExpr_ptr expr = x->getExpr();
  if (instanceof <SQLExpr, SQLName>(expr))
  {
    return findTable(std::dynamic_pointer_cast<SQLName>(expr));
  }

  return nullptr;
}

SchemaObject_ptr SchemaRepository::acceptCreateTable(MySqlCreateTableStatement_ptr x)
{
  SQLExprTableSource_ptr like = x->getLike();
  if (like != nullptr)
  {
    SchemaObject_ptr table = findTable(std::dynamic_pointer_cast<SQLName>(like->getExpr()));
    if (table != nullptr)
    {
      MySqlCreateTableStatement_ptr stmt = std::dynamic_pointer_cast<MySqlCreateTableStatement>(table->getStatement());
      MySqlCreateTableStatement_ptr stmtCloned = std::dynamic_pointer_cast<MySqlCreateTableStatement>(stmt->clone());
      stmtCloned->setName(std::dynamic_pointer_cast<SQLName>(x->getName()->clone()));
      acceptCreateTable(std::dynamic_pointer_cast<SQLCreateTableStatement>(stmtCloned));
      return table;
    }
  }

  return acceptCreateTable(std::dynamic_pointer_cast<SQLCreateTableStatement>(x));
}

SchemaObject_ptr SchemaRepository::acceptCreateTable(SQLCreateTableStatement_ptr x)
{
  SQLCreateTableStatement_ptr x1 = std::dynamic_pointer_cast<SQLCreateTableStatement>(x->clone());
  string_ptr schemaName = x1->getSchema();

  Schema_ptr schema = findSchema(schemaName, BOOL::TRUE);

  SQLSelect_ptr select = x1->getSelect();

  if (select != nullptr)
  {
    SchemaResolveVisitor_Option_list_ptr tmp = std::make_shared<std::list<SchemaResolveVisitor_Option_ptr>>();
    tmp->push_back(SchemaResolveVisitor_Option::ResolveAllColumn);
    select->accept(createResolveVisitor(tmp));

    SQLSelectQueryBlock_ptr queryBlock = select->getFirstQueryBlock();
    SchemaResolveVisitor_Option_list_ptr tmp_empty = std::make_shared<std::list<SchemaResolveVisitor_Option_ptr>>();
    this->resolve(queryBlock, tmp_empty);

    if (queryBlock != nullptr)
    {
      SQLSelectItem_list_ptr selectList = queryBlock->getSelectList();
      for (SQLSelectItem_ptr selectItem : *selectList)
      {
        SQLExpr_ptr selectItemExpr = selectItem->getExpr();
        if (instanceof <SQLExpr, SQLAllColumnExpr>(selectItemExpr) ||
                           (instanceof <SQLExpr, SQLPropertyExpr>(selectItemExpr) && (std::dynamic_pointer_cast<SQLPropertyExpr>(selectItemExpr))->getName()->c_str() == "*"))
        {
          continue;
        }

        SQLColumnDefinition_ptr column = nullptr;
        if (instanceof <SQLExpr, SQLName>(selectItemExpr))
        {
          SQLColumnDefinition_ptr resolvedColumn = std::dynamic_pointer_cast<SQLColumnDefinition>((std::dynamic_pointer_cast<SQLName>(selectItemExpr))->getResolvedColumn());
          if (resolvedColumn != nullptr)
          {
            column = SQLColumnDefinition_ptr(new SQLColumnDefinition());
            column->setDataType(selectItem->computeDataType());
            if (DbType::mysql.name == dbType->name)
            {
              if (resolvedColumn->getDefaultExpr() != nullptr)
              {
                column->setDefaultExpr(std::dynamic_pointer_cast<SQLExpr>(resolvedColumn->getDefaultExpr()->clone()));
              }
              if (resolvedColumn->getConstraints()->size() > 0)
              {
                for (SQLColumnConstraint_ptr constraint : *resolvedColumn->getConstraints())
                {
                  column->addConstraint(std::dynamic_pointer_cast<SQLColumnConstraint>(constraint->clone()));
                }
              }
              if (resolvedColumn->getComment() != nullptr)
              {
                column->setComment(resolvedColumn->getComment());
              }
            }
          }
        }

        if (column == nullptr)
        {
          column = SQLColumnDefinition_ptr(new SQLColumnDefinition());
          column->setDataType(selectItem->computeDataType());
        }

        string_ptr name = selectItem->computeAlias();
        column->setName(name);
        column->setDbType(dbType);
        x1->addColumn(column);
      }
      if (x1->getTableElementList()->size() > 0)
      {
        x1->setSelect(nullptr);
      }
    }
  }

  SQLExprTableSource_ptr like = x1->getLike();
  if (like != nullptr)
  {
    SchemaObject_ptr tableObject = nullptr;

    SQLName_ptr name = like->getName();
    if (name != nullptr)
    {
      tableObject = findTable(name);
    }

    SQLCreateTableStatement_ptr tableStmt = nullptr;
    if (tableObject != nullptr)
    {
      SQLStatement_ptr stmt = tableObject->getStatement();
      if (instanceof <SQLStatement, SQLCreateTableStatement>(stmt))
      {
        tableStmt = std::dynamic_pointer_cast<SQLCreateTableStatement>(stmt);
      }
    }

    if (tableStmt != nullptr)
    {
      SQLName_ptr tableName = x1->getName();
      tableStmt->cloneTo(x1);
      x1->setName(tableName);
      SQLExprTableSource_ptr tmp_empty = nullptr;
      x1->setLike(tmp_empty);
    }
  }

  x1->setSchema(nullptr);

  string_ptr name = x1->computeName();
  SchemaObject_ptr table = schema->findTableOrView(name);
  if (table != nullptr)
  {
    if (x1->isIfNotExists())
    {
      return table;
    }

    // LOG.info("replaced table '" + name + "'");
  }

  table = SchemaObject_ptr(new SchemaObject(schema, name, SchemaObjectType::Table, x1));
  schema->objects.insert(std::make_pair(table->nameHashCode64(), table));
  return table;
}

BOOL_ptr SchemaRepository::acceptDropTable(SQLDropTableStatement_ptr x)
{
  for (SQLExprTableSource_ptr table : *x->getTableSources())
  {
    string_ptr schemaName = table->getSchema();
    Schema_ptr schema = findSchema(schemaName, BOOL::FALSE);
    if (schema == nullptr)
    {
      continue;
    }
    long nameHashCode64 = table->getName()->nameHashCode64();
    schema->objects.erase(nameHashCode64);
  }
  return BOOL::TRUE;
}

// SchemaObject_ptr SchemaRepository::acceptView(SQLCreateViewStatement *x)
// {
//   string_ptr schemaName = x->getSchema();

//   Schema_ptr schema = findSchema(schemaName, BOOL::TRUE);

//   string_ptr name = x.computeName();
//   SchemaObject_ptr view = schema.findTableOrView(name);
//   if (view != nullptr)
//   {
//     return view;
//   }

//   SchemaObject_ptr object = new SchemaObject_ptr(schema, name, SchemaObjectType.View, x.clone());
//   long nameHashCode64 = FnvHash.hashCode64(name);
//   schema.objects.put(nameHashCode64, object);
//   return object;
// }

// BOOL_ptr SchemaRepository::acceptView(SQLAlterViewStatement *x)
// {
//   string_ptr schemaName = x->getSchema();

//   Schema_ptr schema = findSchema(schemaName, BOOL::TRUE);

//   string_ptr name = x.computeName();
//   SchemaObject_ptr view = schema.findTableOrView(name);
//   if (view != nullptr)
//   {
//     return BOOL::FALSE;
//   }

//   SchemaObject_ptr object = new SchemaObject_ptr(schema, name, SchemaObjectType.View, x.clone());
//   schema.objects.put(object.nameHashCode64(), object);
//   return BOOL::TRUE;
// }

BOOL_ptr SchemaRepository::acceptDropIndex(SQLDropIndexStatement_ptr x)
{
  if (x->getTableName() == nullptr)
  {
    return BOOL::FALSE;
  }
  SQLName_ptr table = x->getTableName()->getName();
  SchemaObject_ptr object = findTable(table);

  if (object != nullptr)
  {
    SQLCreateTableStatement_ptr stmt = std::dynamic_pointer_cast<SQLCreateTableStatement>(object->getStatement());
    if (stmt != nullptr)
    {
      stmt->apply(x);
      return BOOL::TRUE;
    }
  }

  return BOOL::FALSE;
}

// BOOL_ptr SchemaRepository::acceptCreateIndex(SQLCreateIndexStatement *x)
// {
//   string_ptr schemaName = x->getSchema();

//   Schema_ptr schema = findSchema(schemaName, BOOL::TRUE);

//   string_ptr name = x.getName().getSimpleName();
//   SchemaObject_ptr object = new SchemaObject_ptr(schema, name, SchemaObjectType.Index, x.clone());
//   schema.objects.put(object.nameHashCode64(), object);

//   return BOOL::TRUE;
// }

// BOOL_ptr SchemaRepository::acceptCreateFunction(SQLCreateFunctionStatement *x)
// {
//   string_ptr schemaName = x->getSchema();
//   Schema_ptr schema = findSchema(schemaName, BOOL::TRUE);

//   string_ptr name = x.getName().getSimpleName();
//   SchemaObject_ptr object = new SchemaObject_ptr(schema, name, SchemaObjectType.Function_ptr, x.clone());
//   schema.functions.put(object.nameHashCode64(), object);

//   return BOOL::TRUE;
// }

// BOOL_ptr SchemaRepository::acceptAlterTable(SQLAlterTableStatement *x)
// {
//   string_ptr schemaName = x->getSchema();

//   if (dbType == DbType_ptr.sqlserver)
//   {
//     SQLName_ptr tableName = x.getTableSource().getName();
//     if (tableName instanceof SQLPropertyExpr)
//     {
//       SQLExpr_ptr owner = ((SQLPropertyExpr)tableName).getOwner();
//       if (owner instanceof SQLPropertyExpr)
//       {
//         schemaName = ((SQLPropertyExpr)owner).getName();
//       }
//     }
//   }

//   Schema_ptr schema = findSchema(schemaName, BOOL::TRUE);
//   SchemaObject_ptr object = schema.findTable(x.nameHashCode64());
//   if (object != nullptr)
//   {
//     SQLCreateTableStatement stmt = (SQLCreateTableStatement)object.getStatement();
//     if (stmt != nullptr)
//     {
//       stmt.apply(x);
//       return BOOL::TRUE;
//     }
//   }

//   return BOOL::FALSE;
// }

BOOL_ptr SchemaRepository::acceptCreateSequence(SQLCreateSequenceStatement *x)
{
  string_ptr schemaName = x->getSchema();
  Schema_ptr schema = findSchema(schemaName, BOOL::TRUE);

  string_ptr name = x->getName()->getSimpleName();
  SchemaObject_ptr object = SchemaObject_ptr(new SchemaObject(schema, name, SchemaObjectType::Sequence));
  schema->objects.insert(std::make_pair(object->nameHashCode64(), object));
  return BOOL::FALSE;
}

BOOL_ptr SchemaRepository::acceptDropSequence(SQLDropSequenceStatement_ptr x)
{
  string_ptr schemaName = x->getSchema();
  Schema_ptr schema = findSchema(schemaName, BOOL::TRUE);

  long nameHashCode64 = x->getName()->nameHashCode64();
  schema->objects.erase(nameHashCode64);
  return BOOL::FALSE;
}

SQLDataType_ptr SchemaRepository::findFuntionReturnType(long functionNameHashCode)
{
  if (functionNameHashCode == FnvHash::Constants::LEN || functionNameHashCode == FnvHash::Constants::LENGTH)
  {
    return (SQLIntegerExpr::DATA_TYPE);
  }

  return nullptr;
}

string_ptr SchemaRepository::loadDDL(string_ptr table)
{
  if (table == nullptr)
  {
    return nullptr;
  }

  table = SQLUtils::normalize(table, schemaDbType);

  if (schemaLoader != nullptr)
  {
    return schemaLoader->loadDDL(nullptr, nullptr, table);
  }
  return nullptr;
}

string_ptr SchemaRepository::loadDDL(string_ptr schema, string_ptr table)
{
  if (table == nullptr)
  {
    return nullptr;
  }

  table = SQLUtils::normalize(table, dbType);
  if (schema != nullptr)
  {
    schema = SQLUtils::normalize(schema, dbType);
  }

  if (schemaLoader != nullptr)
  {
    return schemaLoader->loadDDL(nullptr, schema, table);
  }
  return nullptr;
}

string_ptr SchemaRepository::loadDDL(string_ptr catalog, string_ptr schema, string_ptr table)
{
  if (table == nullptr)
  {
    return nullptr;
  }

  table = SQLUtils::normalize(table, dbType);
  if (schema != nullptr)
  {
    schema = SQLUtils::normalize(schema, dbType);
  }
  if (catalog != nullptr)
  {
    catalog = SQLUtils::normalize(catalog, dbType);
  }

  if (schemaLoader != nullptr)
  {
    return schemaLoader->loadDDL(catalog, schema, table);
  }
  return nullptr;
}

SchemaRepository_SchemaLoader_ptr SchemaRepository::getSchemaLoader()
{
  return schemaLoader;
}

void SchemaRepository::setSchemaLoader(SchemaRepository_SchemaLoader_ptr schemaLoader)
{
  this->schemaLoader = schemaLoader;
}
